﻿// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Browser;
using System.Windows.Controls.Primitives;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;


namespace OnlineBookReader
{
    /// <summary>
    /// The SampleBrowser is used to display interactive samples of controls,
    /// styles, and scenarios.
    /// </summary>
    [ContentProperty("Samples")]
    [TemplatePart(Name = SampleBrowser.SampleSelectionName, Type = typeof(TreeView))]
    [TemplatePart(Name = SampleBrowser.FullScreenButtonName, Type = typeof(ToggleButton))]
   // [TemplatePart(Name = SampleBrowser.SourceListName, Type = typeof(ListBox))]
    [TemplatePart(Name = SampleBrowser.DetailInfoName, Type = typeof(ScrollViewer))]
    [TemplatePart(Name = SampleBrowser.SampleScrollerName, Type = typeof(ScrollViewer))]
    [TemplatePart(Name = SampleBrowser.SamplesTabName, Type = typeof(TabControl))]
    [TemplatePart(Name = SampleBrowser.SourceExpanderName, Type = typeof(Expander))]
    [TemplatePart(Name = SampleBrowser.SampleGridSplitterName, Type = typeof(GridSplitter))]
   // [TemplatePart(Name = SampleBrowser.SampleHeaderName, Type = typeof(TextBlock))]
   // [TemplatePart(Name = SampleBrowser.SampleLevelName, Type = typeof(Label))]
    [TemplatePart(Name = SampleBrowser.SampleDisplayAreaName, Type = typeof(Grid))]
    [TemplatePart(Name = SampleBrowser.RootName, Type = typeof(Grid))]
    [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Samples demonstrate a lot of types.")]
    public sealed class SampleBrowser : Control
    {
        /// <summary>
        /// SampleDisplayArea Grid row number where the source viewer is 
        /// located.
        /// </summary>
       private const int SourceViewerRow = 3;

        /// <summary>
        /// Deep Path Link QueryString Parameter Name.
        /// </summary>
        private const string DeepPathLinkQueryStringParamName = "path";

        #region TemplateParts
        /// <summary>
        /// Name of the sample selection TreeView.
        /// </summary>
        private const string SampleSelectionName = "SampleSelection";

        /// <summary>
        /// Name of the samples TabControl .
        /// </summary>
        private const string SamplesTabName = "SamplesTab";

        /// <summary>
        /// Name of the button that toggles full screen.
        /// </summary>
        private const string FullScreenButtonName = "FullScreenButton";

        /// <summary>
        /// Name of the source list ListBox.
        /// </summary>
        private const string DetailInfoName = "DetailInfo";

        /// <summary>
        /// Name of the source text TextBox.
        /// </summary>
       // private const string SourceTextName = "SourceText";

        /// <summary>
        /// Name of root layout for the Sample Browser.
        /// </summary>
        private const string RootName = "Root";
        private const string SampleScrollerName = "SampleScroller";
        /// <summary>
        /// Name of the grid containing the sample and source file viewer.
        /// </summary>
        private const string SampleDisplayAreaName = "DisplayArea";

        /// <summary>
        /// Name of the expander containing the source file viewer.
        /// </summary>
        private const string SourceExpanderName = "SourceExpander";

        /// <summary>
        /// Name of the GridSplitter that separates the sample from the source
        /// file viewer.
        /// </summary>
        private const string SampleGridSplitterName = "SampleGridSplitter";

        /// <summary>
        /// Name of the TabItem style defined in generic.xaml.
        /// </summary>
        private const string TabItemStyleName = "TabItemStyle";

        /// <summary>
        /// Name of the Sample Header.
        /// </summary>
        private const string SampleHeaderName = "SampleHeader";

        /// <summary>
        /// Name of the Label containing the Sample Level defined in 
        /// generic.xaml.
        /// </summary>
       // private const string SampleLevelName = "SampleLevel";

        /// <summary>
        /// The TreeView used for selecting samples.
        /// </summary>
        private TreeView _sampleSelection;
        private GridSplitter DetailSplitter;
        /// <summary>
        /// Gets or sets the TreeView used for selecting samples.
        /// </summary>
        private TreeView SampleSelection
        {
            get { return _sampleSelection; }
            set
            {
                if (_sampleSelection != null)
                {
                    _sampleSelection.SelectedItemChanged -= OnSelectedTreeChanged;
                }

                _sampleSelection = value;

                if (_sampleSelection != null)
                {
                    _sampleSelection.SelectedItemChanged += OnSelectedTreeChanged;
                    _sampleSelection.LayoutUpdated += OnSampleLayoutUpdated;
                }
            }
        }

        /// <summary>
        /// Gets or sets the root layout.
        /// </summary>
        private Grid SampleRoot { get; set; }
        private ScrollViewer SampleScroller { get; set; }
        /// <summary>
        /// Gets or sets the sample display area grid.
        /// </summary>
        private Grid SampleDisplayArea { get; set; }

        /// <summary>
        /// Gets or sets the grid splitter that separates the sample
        /// from the source viewer.
        /// </summary>
        private GridSplitter SampleGridSplitter { get; set; }

        /// <summary>
        /// Gets or sets the style for the sample tab items.
        /// </summary>
        private Style SampleTabItemStyle { get; set; }

        /// <summary>
        /// Gets or sets The expander that holds the list of files and content area where
        /// they are rendered.
        /// </summary>
        private Expander _sourceExpander { get; set; }

        /// <summary>
        /// Gets or sets the Expander that hosts the samples.
        /// </summary>
        private Expander SourceExpander
        {
            get { return _sourceExpander; }
            set
            {
                if (_sourceExpander != null)
                {
                    _sourceExpander.Expanded -= OnSourceExpanded;
                    _sourceExpander.Collapsed -= OnSourceCollapsed;
                }
                _sourceExpander = value;

                if (_sourceExpander != null)
                {
                    _sourceExpander.Expanded += OnSourceExpanded;
                    _sourceExpander.Collapsed += OnSourceCollapsed;
                }
            }
        }
        public ScrollViewer DetailInfo { get; set; }
        /// <summary>
        /// Gets or sets the tabControl that hosts the samples.
        /// </summary>
        private TabControl SamplesTab { get; set; }

        /// <summary>
        /// The button that toggles full screen view.
        /// </summary>
        private ToggleButton _fullscreenButton;

        /// <summary>
        /// Gets or sets the button that toggles full screen view.
        /// </summary>
        private ToggleButton FullScreenButton
        {
            get { return _fullscreenButton; }
            set
            {
                if (_fullscreenButton != null)
                {
                    _fullscreenButton.Click -= OnToggleFullScreen;
                }

                _fullscreenButton = value;
                if (_fullscreenButton != null)
                {
                    _fullscreenButton.Click += OnToggleFullScreen;
                }
            }
        }

     

        #endregion

        /// <summary>
        /// Gets or sets a reference to the current SampleBrowser control.
        /// </summary>
        public static SampleBrowser Current { get; set; }

        /// <summary>
        /// Gets or sets the items used to populate the TreeView.
        /// </summary>
        private IEnumerable<SampleTreeItem> SampleTreeItems { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the SourceView expander 
        /// is collapsed by the user.
        /// </summary>
        private bool IsSourceViewCollapsed { get; set; }

        /// <summary>
        /// Gets or sets a value indicating the current source file displayed.
        /// </summary>
       // private SourceFile CurrentSourceFile { get; set; }

        /// <summary>
        /// Initializes a new instance of the SampleBrowser class.
        /// </summary>
        /// <param name="sampleTreeItems">Items used to populate the TreeView.</param>
        public SampleBrowser(IEnumerable<SampleTreeItem> sampleTreeItems)
        {
            SampleTreeItems = sampleTreeItems;
            Current = this;
            DefaultStyleKey = typeof(SampleBrowser);
            IsSourceViewCollapsed = true;

            // Get notifications when full screen mode changes
            if (Application.Current != null)
            {
                Application.Current.Host.Content.FullScreenChanged += OnFullScreenChanged;
            }

            CompositionInitializer.SatisfyImports(this);
        }

        /// <summary>
        /// Gets or sets the set of Samples. This must be public because SL doesn't support
        /// non-public reflection which MEF needs to set this property.
        /// </summary>
        [ImportMany("Sample")]
        public Lazy<FrameworkElement, ISampleMetadata>[] Samples { get; set; }
        [ImportMany("DetailInfo")]
        public Lazy<FrameworkElement, ISampleMetadata>[] DetailInfos { get; set; }
        public void PopulateSamplesTab(string viewName,string uri)
        {
            if (SamplesTab == null)
            {
                return;
            }

            // Unhook this event when dynamically before adding new tabs.
            SamplesTab.SelectionChanged -= OnSamplesTabSelectionChanged;

            //IList<TabItem> tabs = SamplesTab.Items.Cast<TabItem>().ToList();
            foreach (object o in SamplesTab.Items)
            {
                TabItem t = o as TabItem;
                SampleBrowserItem sbi= (SampleBrowserItem)t.Header;
                if(sbi.ViewName==viewName)
                {
                    SamplesTab.Items.Remove(o);
                    
                    break;
                }
            }
         
            // Construct a sorted list of samples
            IList<SampleBrowserItem> samples = new List<SampleBrowserItem>();

            foreach (var sample in Samples)
            {
                if (viewName.Equals(sample.Metadata.ViewName))
                {
                    SampleBrowserItem.AddSample(samples, sample, uri);
                }
            }
            // Populate the Tab Control with the samples.
            //foreach (SampleBrowserItem item in samples)
            //{
                
            //}
            TabItem tabItem = new TabItem();
            if (SampleTabItemStyle != null)
            {
                tabItem.Style = SampleTabItemStyle;
            }

            tabItem.Header = samples[0];
            SamplesTab.Items.Add(tabItem);
            

            // Select new
            if (SamplesTab.Items.Count > 0)
            {
                (SamplesTab.Items[SamplesTab.Items.Count-1] as TabItem).IsSelected = true;
                LoadSample();
                SetDetailViewer(viewName, uri);        

            }
            // Hook up this event when done creating the Sample tabs.
            SamplesTab.SelectionChanged += OnSamplesTabSelectionChanged;
        }

        /// <summary>
        /// Expands the Sample TreeView.
        /// </summary>
        /// <param name="sender">The Sender.</param>
        /// <param name="e">Event arguments.</param>
        private void OnSampleLayoutUpdated(object sender, EventArgs e)
        {
            TreeViewItem item = _sampleSelection.ItemContainerGenerator.ContainerFromIndex(0) as TreeViewItem;
            item.IsSelected = true;
            _sampleSelection.LayoutUpdated -= OnSampleLayoutUpdated;
        }
        
        /// <summary>
        /// Retrieve select elements from a control template.
        /// </summary>
        public override void OnApplyTemplate()
        {
            
            base.OnApplyTemplate();
            SampleSelection = GetTemplateChild(SampleSelectionName) as TreeView;
            FullScreenButton = GetTemplateChild(FullScreenButtonName) as ToggleButton;
            DetailInfo = GetTemplateChild(DetailInfoName) as ScrollViewer;
            DetailInfo.SizeChanged += new SizeChangedEventHandler(DetailInfo_SizeChanged);
            SamplesTab = GetTemplateChild(SamplesTabName) as TabControl;
            SampleRoot = GetTemplateChild(RootName) as Grid;
            SampleDisplayArea = GetTemplateChild(SampleDisplayAreaName) as Grid;
            SourceExpander = GetTemplateChild(SourceExpanderName) as Expander;
            //SourceExpander.SizeChanged += new SizeChangedEventHandler(SourceExpander_SizeChanged);
            //SourceExpander.Expanded += new RoutedEventHandler(SourceExpander_Expanded);
            SampleGridSplitter = GetTemplateChild(SampleGridSplitterName) as GridSplitter;
             // Get the Style of the Tab Item to be used when generating the tabs
            if (SampleRoot != null)
            {
                SampleTabItemStyle = SampleRoot.Resources[TabItemStyleName] as Style;
            }
            // Populate the samples
            if (SampleSelection != null)
            {
                SampleSelection.ItemsSource = SampleTreeItems;
            }

            SelectNavigationOnDeepLinkPath();

            // Show the TreeView
            Show(SampleSelection);
        }

       

        void SampleScroller_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.Down)
            { }
        }

        void DetailInfo_SizeChanged(object sender, SizeChangedEventArgs e)
        {
           //WebBrowser browser= ((UserControl)this.DetailInfo.Content).FindName("webBrowser1") as WebBrowser;
           ////ScrollViewer sv=
           //browser.Height =this.DetailInfo.ActualHeight>40? this.DetailInfo.ActualHeight-40:40;
           //browser.Width = this.DetailInfo.ActualWidth>30?DetailInfo.ActualWidth-30:30;
          
        }

        /// <summary>
        /// Change the selected sample.
        /// </summary>
        /// <param name="sender">The samples TreeView.</param>
        /// <param name="e">Event arguments.</param>
        private void OnSelectedTreeChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            SampleTreeItem item = SampleSelection.SelectedItem as SampleTreeItem;
            if (item != null)
            {
                PopulateSamplesTab(item.ViewName, item.Uri);
                SetDetailViewer(item.ViewName,item.Uri);              
            }

            // Reset the CurrentSourceFile tracker
            //CurrentSourceFile = null;
        }
        /// <summary>
        /// SamplesTab selection changed.
        /// </summary>
        /// <param name="sender">The Sender.</param>
        /// <param name="e">Event arguments.</param>
        private void OnSamplesTabSelectionChanged(object sender, SelectionChangedEventArgs e)
        {

            TabItem t = e.AddedItems[0] as TabItem;
            SampleBrowserItem item = (SampleBrowserItem)t.Header;
            LoadSample();
            SetDetailViewer(item.ViewName, item.Uri);  
        }
        /// <summary>
        /// Collapse the Source File Viewer.
        /// </summary>
        /// <param name="sender">The Sender.</param>
        /// <param name="e">Event arguments.</param>
        private void OnSourceCollapsed(object sender, RoutedEventArgs e)
        {
            ExpandSampleDisplayArea();
            if (SampleGridSplitter != null)
            {
                SampleGridSplitter.Visibility = Visibility.Collapsed;
            }

            IsSourceViewCollapsed = true;
        }

        /// <summary>
        /// Expands the Source File Viewer.
        /// </summary>
        /// <param name="sender">The Sender.</param>
        /// <param name="e">Event arguments.</param>
        private void OnSourceExpanded(object sender, RoutedEventArgs e)
        {
            ExpandSourceViewerArea();
            if (SampleGridSplitter != null)
            {
                SampleGridSplitter.Visibility = Visibility.Visible;
            }

            IsSourceViewCollapsed = false;
        }

      

        /// <summary>
        /// Toggle the full screen view of the samples.
        /// </summary>
        /// <param name="sender">The ToggleButton.</param>
        /// <param name="e">Event arguments.</param>
        private void OnToggleFullScreen(object sender, RoutedEventArgs e)
        {
            Application.Current.Host.Content.IsFullScreen = (bool)FullScreenButton.IsChecked;
        }

        /// <summary>
        /// Handle full screen changes to the application.
        /// </summary>
        /// <param name="sender">The Sender.</param>
        /// <param name="e">Event arguments.</param>
        private void OnFullScreenChanged(object sender, EventArgs e)
        {
            // Uncheck the ToggleButton if the application quit full screen mode
            if (!Application.Current.Host.Content.IsFullScreen && FullScreenButton != null)
            {
                FullScreenButton.IsChecked = false;
            }
        }

        /// <summary>
        /// Change the selected sample.
        /// </summary>
        private void LoadSample()
        {
            //SetSourceViewer(null);
            TabItem currentTab = SamplesTab.SelectedItem as TabItem;

            if (currentTab == null)
            {
                return;
            }
            
            // Get the new sample
            SampleBrowserItem item = currentTab.Header as SampleBrowserItem;
            currentTab.Content = item.GetSample();
            //SetDetailViewer(viewName, uri);   
        }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="treeItem"></param>
        public void SetDetailViewer(string viewName,string uri)
        {
            Type t = null;
            foreach (var detail in DetailInfos)
            {
                if (viewName.Equals(detail.Metadata.ViewName))
                {
                    t = detail.Value.GetType();
                    break;
                }
                else if(detail.Metadata.ViewName=="htmlView")
                {
                    t = detail.Value.GetType();
                    break;
                }
                
            }

            if (t != null)
            {
               
                DetailInfo di = new DetailInfo(uri, t);
                DetailInfo.Content = di.GetSample();
            }

        }

        /// <summary>
        /// Expands the Source Viewer Area when there are source files to 
        /// display.
        /// </summary>
        private void ExpandSourceViewerArea()
        {
            if (SampleDisplayArea != null)
            {
                SampleDisplayArea.RowDefinitions[SourceViewerRow].Height = new GridLength(SampleDisplayArea.ActualHeight / 2, GridUnitType.Pixel);
            }
        }

        /// <summary>
        /// Expands the Sample Display Area when there is no Source File to 
        /// display. 
        /// </summary>
        private void ExpandSampleDisplayArea()
        {
            if (SampleDisplayArea != null)
            {
                SampleDisplayArea.RowDefinitions[SourceViewerRow].Height = new GridLength(1, GridUnitType.Auto);
            }
        }

        /// <summary>
        /// Helper method to begin a storyboard associated with a control.
        /// </summary>
        /// <param name="control">Control containing a storyboard to be played.
        /// </param>
    

        #region 
        private static void Show(Control control)
        {
            Storyboard storyBoard = control.Resources["Show"] as Storyboard;
            if (storyBoard != null)
            {
                storyBoard.Begin();
            }
        }

        /// <summary>
        /// Select a TreeViewItem and a TabItem used for navigation based on the query string
        /// deep link path. 
        /// </summary>
        private void SelectNavigationOnDeepLinkPath()
        {
            // Select a TreeViewItem based on the 1st and 2nd deep path levels
            if (IsDeepPathLinkSpecified)
            {
                if (!string.IsNullOrEmpty(GetPathForLevel(0)))
                {
                    SampleTreeItem firstDeepPathLevelSampleItem =
                        SampleSelection.Items.OfType<SampleTreeItem>().SingleOrDefault(
                            t => t.TreeItemName == GetPathForLevel(0));

                    if (firstDeepPathLevelSampleItem != null)
                    {
                        if (string.IsNullOrEmpty(GetPathForLevel(1)))
                        {
                            SelectTreeViewItemFor(firstDeepPathLevelSampleItem);
                        }
                        else
                        {
                            SampleTreeItem secondDeepPathLevelSampleItem =
                                firstDeepPathLevelSampleItem.Items.OfType<SampleTreeItem>().SingleOrDefault(
                                    t => t.TreeItemName == GetPathForLevel(1));

                            if (secondDeepPathLevelSampleItem != null)
                            {
                                SelectTreeViewItemFor(firstDeepPathLevelSampleItem, secondDeepPathLevelSampleItem);
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Selects a tree view item based on an item.
        /// </summary>
        /// <param name="firstLevelItem">Item that correlates to a the TreeViewItem.</param>
        private void SelectTreeViewItemFor(SampleTreeItem firstLevelItem)
        {
            SampleSelection.Loaded += (s, args) =>
            {
                ((TreeViewItem)SampleSelection.ItemContainerGenerator.ContainerFromItem(firstLevelItem)).IsSelected = true;
            };
        }
        /// <summary>
        /// Selects a tree view item based on an item.
        /// </summary>
        /// <param name="firstLevelItem">Item that correlates to a the first level TreeViewItem.</param>
        /// <param name="secondLevelItem">Item that correlates to a the second level TreeViewItem.</param>
        private void SelectTreeViewItemFor(SampleTreeItem firstLevelItem, SampleTreeItem secondLevelItem)
        {
            SampleSelection.Loaded += (s, args) =>
            {
                TreeViewItem firstLevelTreeViewItem = (TreeViewItem)
                    SampleSelection.ItemContainerGenerator.ContainerFromItem(firstLevelItem);
                TreeViewItem secondLevelTreeViewItem = (TreeViewItem)
                    firstLevelTreeViewItem.ItemContainerGenerator.ContainerFromItem(secondLevelItem);
                secondLevelTreeViewItem.IsSelected = true;

                // check if 3rd level deep link path has a correlating TabItem
                if (!string.IsNullOrEmpty(GetPathForLevel(2)))
                {
                    TabItem tabItemToSelect = SamplesTab.Items.OfType<TabItem>().SingleOrDefault(
                    t => ((SampleBrowserItem)t.Header).Name == GetPathForLevel(2));

                    if (tabItemToSelect != null)
                    {
                        tabItemToSelect.IsSelected = true;
                    }
                }
            };
        }
        /// <summary>
        /// Gets a value indicating whether the Deep Path Link query string parameter was specified.
        /// </summary>
        private static bool IsDeepPathLinkSpecified
        {
            get
            {
                if (!HtmlPage.IsEnabled)
                {
                    return false;
                }

                if (HtmlPage.Document == null)
                {
                    return false;
                }

                return HtmlPage.Document.QueryString.Keys.Contains(DeepPathLinkQueryStringParamName);
            }
        }

        /// <summary>
        /// Returns the Initial Deep Path Link Lookup.
        /// </summary>
        /// <param name="level">Deep path link level.</param>
        /// <returns>The deep path for that level.</returns>
        private static string GetPathForLevel(int level)
        {
            if (!IsDeepPathLinkSpecified)
            {
                return string.Empty;
            }

            string DeepLinkPathRawValue = HtmlPage.Document.QueryString[DeepPathLinkQueryStringParamName];
            string DeepLinkPathDecodedValue = HttpUtility.UrlDecode(DeepLinkPathRawValue);
            string[] deepLinkPath = DeepLinkPathDecodedValue.Split('|');

            if (deepLinkPath.Length - 1 >= level)
            {
                return deepLinkPath[level];
            }
            else
            {
                return string.Empty;
            }
        }
        #endregion



    }
}
